from PIL import Image
import random
import numpy
import time


# 判断方式
class JugMethod:

    # funclist [方法1,方法2...]
    def __init__(self, funclist, parmlist=None):
        self.funclist = funclist
        if parmlist is None:
            parmlist = self.rdom_parm()
        self.parmlist = parmlist

    # ####################################### hello world ~
    ''' # # # # # # # 数  据  准  备 # # # # # # #
|     |   |  | | || data preparation || | |  |   |     |
*-------------------------------======================================'''

    def lut(self):
        return self.block[0] + self.block[1] + self.block[3]  # 左上 上三角

    def llt(self):
        return self.block[3] + self.block[6] + self.block[7]  # 左下 下三角

    def rut(self):
        return self.block[1] + self.block[2] + self.block[5]  # 右上 上三角

    def rlt(self):
        return self.block[5] + self.block[7] + self.block[8]  # 右下 下三角

    def ls(self):
        return self.block[0] + self.block[8]  # 左->右 斜线(不包含中心点) \

    def rs(self):
        return self.block[2] + self.block[6]  # 右->左 斜线(不包含中心点) /

    def cs(self):
        return self.block[3] + self.block[5]  # 横线(不包括中心点)  -

    def vs(self):
        return self.block[1] + self.block[7]  # 竖线(不包括中心点)  |

    def rdom(self, n=1):  # 随机取n个非中心值
        if n >= 8:
            return sum(self.other)
        elif n <= 0:
            return 0

        tmp = self.other.copy()
        lis = []
        for i in range(n):
            t = random.choice(tmp)
            lis.append(t)
            tmp.remove(t)
        return sum(lis)

    # ####################################### hello world ~
    '''# # # # # # # 判  断  方  法 # # # # # # #
|     |   |  | | || Judgment Method || | |  |   |     |
*-------------------------------======================================'''

    # 传入参数说明
    # func_将会调用的方法编号 支持列表形式，一般情况下默认为单值
    # x_注入的参数
    # *args_子方法编号   当func取列表时，需要一一对应且存在
    def way_and(self, func, x, *args):
        k = 0
        for i in args:
            if isinstance(func, list):
                f = func[k]
                k += 1
            else:
                f = func

            funcname = f'way_{f}_{i}'
            if not getattr(self, funcname)(x):
                return False
        return True

    def way_or(self, func, x=40000, *args):
        k = 0
        for i in args:
            if isinstance(func, list):
                f = func[k]
                k += 1
            else:
                f = func

            funcname = f'way_{f}_{i}'
            if getattr(self, funcname)(x):
                return True
        return False

    '''
# 1 # 1 ## 1 1 ### 一 # 1 #### 一 ## 1 ########## 一 #####################
    # 玄学判断法，x稳定于40000左右，提取线稿
    '''

    def way_1_mod(self, n, x):
        if abs(n - self.n) ** 2 > x:
            return True
        return False

    def way_1_1(self, x):
        n = int(self.lut() / 3)
        return self.way_1_mod(n, x)

    def way_1_2(self, x):
        n = int(self.ls() / 2)
        return self.way_1_mod(n, x)

    def way_1_3(self, x):
        n = int((self.block[0] + self.block[3] + self.block[5] + self.block[6]) / 4)
        return self.way_1_mod(n, x)

    def way_1_4(self, x):
        n = int((self.block[1] + self.block[4]) / 2)
        return self.way_1_mod(n, x)

    def way_1_5(self, x, i=2):
        """随机取{i}个其他值的均值"""
        n = int((self.rdom(i)) / i)
        return self.way_1_mod(n, x)

    '''
# 2 # 2 ## 2 2 ### 二 # 2 #### 二 ## 2 ########## 二 #####################    
    # 硬性判断，灰度像素分布于0[黑]-255[白]，可以保留暗部
    '''

    def way_2_1(self, x=64):
        """x值以下的内容为真"""
        if self.n < x:
            return True
        return False

    def way_2_2(self, x=64):
        """x值以下的内容为真"""
        if self.n < x:
            return True
        return False

    '''
# 3 # 3 ## 3 3 ### 三 # 3 #### 三 ## 3 ########## 三 #####################
    # 对于所有分散在周围的像素取色，生成噪点
    '''

    def way_3_1(self, x=0):
        """中心点与外围均值比大小,x与中心点值相加"""
        num = sum(self.other)
        num = int(num / 8)
        if self.n + x < num:
            return True
        return False

    '''
# 4 # 4 ## 4 4 ### 四 # 4 #### 四 ## 4 ########## 四 #####################
    # 玄学检测
    '''

    def way_4_1(self, x=255):
        n1 = random.choice(self.other)
        n2 = sum(self.other) % x
        if n1 > n2:
            return True
        return False

    '''
# 5 # 5 ## 5 5 ### 五 # 5 #### 五 ## 5 ########## 五 #####################
    '''

    def way_5_mod(self, n, x):
        if self.allin - n * 2 < x:
            return True
        return False

    # 斜向 \
    def way_5_1(self, x):
        n = self.ls() + self.n
        self.way_5_mod(n, x)

    # 斜向 /
    def way_5_2(self, x):
        n = self.rs() + self.n
        self.way_5_mod(n, x)

    # 横向 -
    def way_5_3(self, x):
        n = self.cs() + self.n
        self.way_5_mod(n, x)

    # 竖向 |
    def way_5_4(self, x):
        n = self.vs() + self.n
        self.way_5_mod(n, x)

    # ####################################### hello world ~
    '''# # # # # # # 方  法  装  填 # # # # # # #
 |     |   |  | | || method to fill || | |  |   |     |
*-------------------------------======================================'''

    def just_doit(self, block):
        self.data_on(block)
        lis = self.doit()
        return lis

    # block为3x3的矩阵
    def data_on(self, block):
        self.other = block[:4] + block[5:]
        self.block = block
        self.n = block[4]
        self.allin = sum(block)

    def doit(self):
        """批量执行"""
        results = []
        for i in range(len(self.funclist)):
            result = getattr(self, self.funclist[i])(*self.parmlist[i])
            results.append(result)
        return results

    def rdom_parm(self):
        """随机产出一组参数"""
        lis = []
        for func in self.funclist:
            if func == 'way_and' or func == 'way_or':
                i = 1
                datum = self.base_case[i - 1]
                dat = int(datum * 0.1)
                rdom = random.randint(datum - dat, datum + dat)
                lis.append([i, rdom, 1, 2, 3, 4])
            else:
                choice = int(func[4])
                datum = self.base_case[choice - 1]
                dat = int(datum * 0.1)
                if dat == 0:
                    dat = random.randint(0, 10)
                rdom = random.randint(datum - dat, datum + dat)
                lis.append([rdom])
        return lis

    base_case = [40000, 64, 0, 255, 800]


class IM:
    # 原型 图片类型
    def __init__(self, prototype, pictype='jpeg'):
        name = str(prototype) + '.' + pictype
        img = Image.open(name)

        self.prototype = str(prototype)
        self.pictype = pictype
        self.width, self.height = img.size

        self.canvas = []  # 画布
        self.tmp = {}  # 缓存
        self.parameter = None  # 参数   预期方式:二维列表    [[每组参数],[]...]
        self.function = None  # 所用方法列表
        self.jug = None  # 渲染器

    '''# # # # # # # 准  备  阶  段 # # # # # # #
        |   |  | | || ready stage || | |  |   |
*-------------------------------======================================'''

    # # 基础功能|basic function ############################
    def print_progress(self, row):
        """打印百分比"""
        percentage = row * 100 / self.height
        if percentage > 100:
            percentage = random.randint(self.under * 100, 10000) / 100
        self.under = percentage
        print('%.2f' % percentage, end='%\n')

    under = 0

    def gray_area(self, x):
        """灰阶"""
        if x > 240:
            return 255
        elif x <= 240 and x > 180:
            return 200
        elif x <= 180 and x > 100:
            return 150
        elif x <= 100 and x > 60:
            return 90
        else:
            return 0

    def gray(self, p):
        if isinstance(p, numpy.ndarray):
            return int((p[0] + p[1] + p[2]) / 3)
        return p

    def open_img(self, way, kind):
        image = Image.open(way)
        img = image.convert(kind)
        return numpy.asarray(img)

    # # 画布处理|Canvas processing #######[画布:canvas:用于记录位图结果]#############
    def new_canvas(self, name):
        self.canvas.append([name, [[255] * self.width for x in range(self.height)]])

    def save_canvas(self):
        for i in self.canvas:
            self.tmp[i[0]] = i[1]
        self.canvas = []

    # # 缓存处理|cache processing #######[备用件:tmp:用于记录位图结果]#############
    def save_temp(self):
        for tag, data in self.tmp.items():
            image = Image.fromarray(numpy.uint8(data))
            t = (time.time() % 1000) * 1000
            css = f'_{self.prototype}_{tag}_%d.{self.pictype}' % t
            image.save(css)

    def reset_temp(self):
        self.tmp = {}

    # # 参数处理|parameter handling ######[参数:parameter:用于记录所需参数]############################
    def get_parm(self, lis):
        self.parameter = lis

    def add_parm(self, li):
        self.parameter.append(li)

    def reset_parm(self):
        self.parameter = []

    # # 方法使用|method usage ######[方法:function:用于注册所用渲染模式]############################
    def get_func(self, lis):
        self.function = lis

    def add_func(self, *args):
        for i in args:
            self.function.append(i)

    def reset_func(self):
        self.function = []

    # # 渲染器|Renderer ####[渲染器:jug:用于单元判断各矩阵]###########
    def reset_jug(self):
        self.jug = JugMethod(self.function, self.parameter)

    '''# # # # # # # 功  能  整  合 # # # # # # #
   |   |  | | || function integration || | |  |   |
*-------------------------------======================================'''

    def reset(self, funclist, parmlist=None):
        self.reset_temp()

        if parmlist is not None:
            self.reset_parm()
            self.get_parm(parmlist)

        self.reset_func()
        self.get_func(funclist)

        self.reset_jug()

    # # 图像间方法|inter-image method ###############
    def add(self, im1, im2):
        """累加"""
        self.canvas = [['add', im1 + im2]]
        self.save_canvas()

    # lis--->[[name,base_img,type,uper_img,type]]
    def eloop(self, lis):
        """仅适合单步执行的方法！！"""
        name = []
        base = []
        uper = []
        n = len(lis)  # 获取执行数量
        for i in range(n):
            name.append(lis[i][0])
            base.append(self.open_img(lis[i][1], lis[i][2]))
            uper.append(self.open_img(lis[i][3], lis[i][4]))
            self.new_canvas(name[i])  # 新建画布

        for i in range(self.height):  # 缩小范围至像素，并打印进度
            self.print_progress(i)
            for j in range(self.width):

                for k in range(n):  # 按照方法处理
                    getattr(self, name[k])(k, i, j, base[k], uper[k])

        self.save_canvas()  # 保存

    def e1(self, k, i, j, im1, im2):
        """毛玻璃效果"""
        if self.gray(im1[i][j]) < 60:
            random_point1 = random.randint(400, 1000) / 1000
            random_point2 = random.randint(990, 1000) / 1000
            self.canvas[k][1][i][j] = im2[int(i * random_point2)][int(j * random_point2)]
        else:
            try:
                self.canvas[k][1][i][j] = [255, 255, 255]
            except:
                pass

    def e2(self, k, i, j, im1, im2):
        """叠图"""
        if self.gray(im1[i][j]) < 64:
            self.canvas[k][1][i][j] = im2[i][j]
        else:
            self.canvas[k][1][i][j] = im1[i][j]

    def e3(self, k, i, j, im1, im2):
        """暂定"""
        if self.gray(im1[i][j]) < 64:
            self.canvas[k][1][i][j] = (im2[int(i * random.randint(0, 1))][j] + im1[i][j]) / 2
            self.canvas[k][1][i][j] = self.gray_area(self.gray(self.canvas[k][1][i][j]))

    # # 图像拆分方法|inter-image method ###############
    block_status = [(-1, -1), (0, -1), (1, -1),
                    (-1, 0), (0, 0), (1, 0),
                    (-1, 1), (0, 1), (1, 1)]

    # lis--->[base_img,]
    def s(self, lis):
        """我已经被自己写晕了"""
        name = []
        m = len(self.function)
        n = len(lis)  # 获取执行数量
        for z in range(n):
            for j in range(m):
                func = self.function[j].strip('way_')
                parm = self.jug.parmlist[j]
                self.new_canvas(f's_{func}_{parm}')  # 新建画布

            image = lis[z]
            im = self.open_img(image, 'L')

            for i in range(1, self.height - 1):  # 缩小范围至像素，并打印进度
                self.print_progress(i)
                for j in range(1, self.width - 1):

                    block = []
                    for k in self.block_status:
                        block.append(im[i + k[0]][j + k[1]])

                    results = self.jug.just_doit(block)

                    for k in range(m):
                        if results[k]:
                            self.canvas[k][1][i][j] = 0

        self.save_canvas()  # 保存


class Factor():
    默认参数 = {1: 40000, 2: 64, 3: 0, 4: 255, 5: 800}

    x = IM(1, 'jpg')
    func = ['way_1_1', 'way_1_2', 'way_1_3', 'way_1_4', 'way_1_5', 'way_2_1',
            'way_3_1', 'way_4_1', 'way_5_1', 'way_5_2', 'way_5_3', 'way_5_4']
    parm = [[36000], [35000], [34000], [33000], [32000], [60], [-2], [600], [400],[440],[480],[360]]
    x.get_parm(parm)
    x.get_func(func)
    x.reset_jug()
    lis = ['1.jpg']
    x.s(lis)

    func = ['way_and']
    parm = [[5, 1200, 1, 2, 3]]
    x.get_func(func)
    x.get_parm(parm)
    x.reset_jug()
    x.s(lis)

    lis = [['e1', '3.jpg', 'RGB', '1.jpg', 'RGB'],
           ['e2', '3.jpg', 'L', '1.jpg', 'L'],
           ['e3', '3.jpg', 'L', '1.jpg', 'L']]
    x.eloop(lis)

    x.save_temp()


x = Factor()
